#include "dfa.h"
#include "grate_constants.h"
#include <cstring>
#include <cmath>

dfa::dfa(int _size, int _alph_size){
  size = _size;
  alph_size = _alph_size;
  edges = new int [size * alph_size];
  memset(edges, 0, sizeof(int) * size * alph_size);
  total = 1;
  words_num = 0;
}

dfa::~dfa(){
  delete[] edges;
}

int* dfa::operator [](int v){
  return edges + v * alph_size;
}

const bool dfa::add_word(const char *word){
  words_num++;
  int cv = 1, i;
  for (i=0; word[i+1]; i++){
    int c = word[i]-'a';
    if (!edges[cv*alph_size + c]){
      total++;
      if (total >= size){
        return false;
      }
      edges[cv*alph_size + c] = total;
    }
    cv = edges[cv*alph_size + c];
  }
  edges[cv*alph_size + word[i]-'a'] = -1;
  return true;
}

const bool dfa::bad_suffix_trie(const char * buff, const int len, const char dir) const{
  int cv = 1, i, cur = 0;
  int sp = 0, fp = len;
  if (dir < 0){
    sp = len - 1;
    fp = -1;
  }
  char bij[MAX_ALPH_SIZE];
  memset(bij, 0, sizeof(char)*alph_size);
  for (i=sp; i!=fp; i+=dir){
    if (!bij[buff[i]-'a']){
      bij[buff[i]-'a'] = 'a' + cur;
      cur++;
    }
    int c = bij[buff[i]-'a'] - 'a';
    int zv = edges[cv * alph_size + c];
    if (!zv) return false;
    if (zv < 0) return true;
    cv = zv;
  }
  return false;
}

dfa * create_dfa(input_data & INPUT, int size){
  int dsize;
  if (size != -1){
    dsize = size;
  }
  else{ // define size automatically
    double max_size = INPUT.ROOT_LENGTH * pow((double)INPUT.ALPH_SIZE, (double)INPUT.ROOT_LENGTH);
    if (sizeof(int) * max_size * INPUT.ALPH_SIZE < LITTLE_MEMORY){
      dsize = (int)max_size + 1;
    }
    else{
      dsize = DFA_MEMORY_STEP;
      while (1){
        try{
          int * buff = new int [(dsize + DFA_MEMORY_STEP) * INPUT.ALPH_SIZE];
          delete[] buff;
          dsize += DFA_MEMORY_STEP;
        }
        catch(...){
          break;
        }
      }
      dsize >>= 1;
    }
  }
  return new dfa(dsize, INPUT.ALPH_SIZE);
}